//
//  AISUPnPDevice.m
//  AISUPnP
//
//  Created by Ares on 1/26/15.
//  Copyright (c) 2015 Ares. All rights reserved.
//

#import "AISUPnPDevice.h"
#import "AISUPnPService.h"
#import "AISSSDPMessage.h"
#import "AISUPnPIcon.h"
#import "GDataXMLNode.h"

#define UPNP_DEVICE_TYPE_DMR "urn:schemas-upnp-org:device:MediaRenderer:1"
#define UPNP_DEVICE_TYPE_DMS "urn:schemas-upnp-org:device:MediaServer:1"

#define XML_TAG_DEVICE @"device"
// sub of device
#define XML_TAG_UDN @"UDN"
#define XML_TAG_FRIENDLY_NAME @"friendlyName"
#define XML_TAG_DEVICE_TYPE @"deviceType"
#define XML_TAG_MANUFACTURER @"manufacturer"
#define XML_TAG_MODEL_NAME @"modelName"
#define XML_TAG_MODEL_NUMBER @"modelNumber"
#define XML_TAG_ICON_LIST @"iconList"
#define XML_TAG_SERVICE_LIST @"serviceList"

// sub of iconList
#define XML_TAG_ICON @"icon"
// sub of icon
#define XML_TAG_MIMETYPE @"mimetype"
#define XML_TAG_WIDTH @"width"
#define XML_TAG_HEIGHT @"height"
#define XML_TAG_DEPTH @"depth"
#define XML_TAG_URL @"url"

// sub of serviceList
#define XML_TAG_SERVICE @"service"
// sub of service
#define XML_TAG_SERVICE_TYPE @"serviceType"
#define XML_TAG_SERVICE_ID @"serviceId"
#define XML_TAG_CONTROL_URL @"controlURL"
#define XML_TAG_EVENT_SUB_URL @"eventSubURL"
#define XML_TAG_SCPDURL @"SCPDURL"

@interface AISUPnPDevice()
{
    
}

@end

@implementation AISUPnPDevice

- (id)initWithMessage:(AISSSDPMessage *)message
{
    self = [super init];
    if (nil != self)
    {
        _uniqueServiceName = message.uniqueServiceName;
        _host = message.fromHost;
        _port = message.fromPort;
        _location = message.location;
        
        NSString *absLocation = nil;
        if ([message.location hasPrefix:@"http://"])
        {
            absLocation = message.location;
        }
        else
        {
            absLocation = [NSString stringWithFormat:@"http://%@/%@", message.fromHost, message.location];
        }
        
        _iconList = [[NSMutableArray alloc] initWithCapacity:0];
        _serviceList = [[NSMutableArray alloc] initWithCapacity:0];
        _rawDescriptionData = [self loadDescriptionFromURL:absLocation];
        [self updateDeviceWithDescriptionData:_rawDescriptionData];
    }
    
    return self;
}

- (NSData *)loadDescriptionFromURL:(NSString *)urlString;
{
    NSData *data = nil;
    NSURL *url = [NSURL URLWithString:urlString];
    if (nil != url)
    {
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        NSURLResponse *response = nil;
        NSError *err = nil;
        data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
    }
    
    return data;
}

- (void)updateDeviceWithDescriptionData:(NSData *)data
{
    if (nil == data)
    {
        NSLog(@"No Description Data from: %@", self.location);
        return;
    }
    
    NSError *err = nil;
    GDataXMLDocument *xmlDoc = [[GDataXMLDocument alloc] initWithData:data options:0 error:&err];
    if (nil != err)
    {
        NSLog(@"Parse XML Description Error: %@", err.description);
        return;
    }
    
    GDataXMLElement *rootElement = [xmlDoc rootElement];
    NSArray *elemArray = [rootElement elementsForName:XML_TAG_DEVICE];
    if ([elemArray count] > 0)
    {
        [self updateDeviceInfoWithDeviceElement:[elemArray objectAtIndex:0]];
    }
}

- (void)updateDeviceInfoWithDeviceElement:(GDataXMLElement *)element
{
    if (nil == element)
    {
        return;
    }
    
    self.uniqueDeviceName = [[[element elementsForName:XML_TAG_UDN] objectAtIndex:0] stringValue];
    self.friendlyName = [[[element elementsForName:XML_TAG_FRIENDLY_NAME] objectAtIndex:0] stringValue];
    self.deviceType = [[[element elementsForName:XML_TAG_DEVICE_TYPE] objectAtIndex:0] stringValue];
    self.manufacturer = [[[element elementsForName:XML_TAG_MANUFACTURER] objectAtIndex:0] stringValue];
    self.modelName = [[[element elementsForName:XML_TAG_MODEL_NAME] objectAtIndex:0] stringValue];
    self.modelNumber = [[[element elementsForName:XML_TAG_MODEL_NUMBER] objectAtIndex:0] stringValue];
    
    GDataXMLElement *xmlElement = nil;
    NSArray *elemArray = nil;
    
    elemArray = [element elementsForName:XML_TAG_ICON_LIST];
    xmlElement = [elemArray objectAtIndex:0];
    if (nil != xmlElement)
    {
        [self updateIconListWithIconListElement:xmlElement];
    }
    
    elemArray = [element elementsForName:XML_TAG_SERVICE_LIST];
    xmlElement = [elemArray objectAtIndex:0];
    if (nil != xmlElement)
    {
        [self updateServiceListWithServiceListElement:xmlElement];
    }
}

- (void)updateIconListWithIconListElement:(GDataXMLElement *)element
{
    if (nil == element)
    {
        return;
    }
    
    NSArray *eleArray = [element elementsForName:XML_TAG_ICON];
    for (GDataXMLElement *xmlElement in eleArray)
    {
        AISUPnPIcon *icon = [[AISUPnPIcon alloc] init];
        icon.mimeType = [[[xmlElement elementsForName:XML_TAG_MIMETYPE] objectAtIndex:0] stringValue];
        icon.width = [[[[xmlElement elementsForName:XML_TAG_WIDTH] objectAtIndex:0] stringValue] integerValue];
        icon.height= [[[[xmlElement elementsForName:XML_TAG_HEIGHT] objectAtIndex:0] stringValue] integerValue];
        icon.depth = [[[[xmlElement elementsForName:XML_TAG_DEPTH] objectAtIndex:0] stringValue] integerValue];
        icon.url = [[[xmlElement elementsForName:XML_TAG_URL] objectAtIndex:0] stringValue];
        [self.iconList addObject:icon];
    }
}

- (void)updateServiceListWithServiceListElement:(GDataXMLElement *)element
{
    if (nil == element)
    {
        return;
    }
    
    NSArray *eleArray = [element elementsForName:XML_TAG_SERVICE];
    for (GDataXMLElement *xmlElement in eleArray)
    {
        AISUPnPService *service = [[AISUPnPService alloc] init];
        service.serviceType = [[[xmlElement elementsForName:XML_TAG_SERVICE_TYPE] objectAtIndex:0] stringValue];
        service.serviceId = [[[xmlElement elementsForName:XML_TAG_SERVICE_ID] objectAtIndex:0] stringValue];
        service.controlURL = [[[xmlElement elementsForName:XML_TAG_CONTROL_URL] objectAtIndex:0] stringValue];
        service.eventSubURL = [[[xmlElement elementsForName:XML_TAG_EVENT_SUB_URL] objectAtIndex:0] stringValue];
        service.SCPDURL = [[[xmlElement elementsForName:XML_TAG_SCPDURL] objectAtIndex:0] stringValue];
        [self.serviceList addObject:service];
    }
}

@end
